package monitor.model.dao;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;

import monitor.model.entity.Car;
import monitor.view.util.Utils;

/**
 * Singleton DAO class
 * 
 * Implements CRUD operations for cars. 
 * CRUD operations are used to register, delete or retrieve cars.
 *
 */
public class CarDAO {
	private static final String ALL_CARS = "AllCars";
	private static final String OWNER_CARS = "OwnerCars";
	private DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
	
	private static CarDAO instance;
	
	private CarDAO() {
	}
	
	public static CarDAO getInstance() {
		if(instance == null) {
			instance = new CarDAO();
		}
		return instance;
	}
	
	public void insert(Car car) {
		String carId = Utils.generateCarId();
		User user = UserServiceFactory.getUserService().getCurrentUser();
		String owner = user.getNickname();
		car.setId(carId);

		Key ownerKey = KeyFactory.createKey(ALL_CARS, owner);
		Entity entity = new Entity(OWNER_CARS, ownerKey);
		
		Utils.fillGAEEntity(entity, car);

		Key key = this.datastoreService.put(entity);
		car.setKey(key);
	}
	
	public List<Car> retrieveAllCars() {
		List<Car> availableCars = new LinkedList<Car>();
		
		User user = UserServiceFactory.getUserService().getCurrentUser();
		String owner = user.getNickname();
		Key ownerKey = KeyFactory.createKey(ALL_CARS, owner);
		Query query = new Query(OWNER_CARS, ownerKey).setAncestor(ownerKey);

		PreparedQuery preparedQuery = this.datastoreService.prepare(query);
		Iterator<Entity> availableCarsIter = preparedQuery.asIterator();

		while (availableCarsIter.hasNext()) {
			Entity entity = availableCarsIter.next();
			Car car = new Car();
			car.setKey(entity.getKey());
			car.getAttributes().putAll(entity.getProperties());
			availableCars.add(car);
		}
		
		return availableCars;
	}
	
	public void deleteCar(Car car) {
		Key key = car.getKey();
		this.datastoreService.delete(key);
	}
	
	public Car getCarById(String id) {
		User user = UserServiceFactory.getUserService().getCurrentUser();
		String owner = user.getNickname();
		Key ownerKey = KeyFactory.createKey(ALL_CARS, owner);
		
		Query query = new Query(OWNER_CARS, ownerKey).setAncestor(ownerKey);
		
		query.addFilter(Car.ATTR_ID, FilterOperator.EQUAL, id);
		PreparedQuery preparedQuery = this.datastoreService.prepare(query);
		Entity entity = preparedQuery.asSingleEntity();
		Car car = new Car();
		if(entity == null) {
			return null;
		}
		car.getAttributes().putAll(entity.getProperties());
		return car;
	}
}
